package permit

import (
	"context"
	"fmt"
	"gitee.com/hxchjm/go-admin/pkg/cas"
	"gitee.com/hxchjm/go-admin/pkg/ecode"
	"gitee.com/hxchjm/go-admin/pkg/jwtauth"
	"github.com/casbin/casbin/v2/util"
	"github.com/gin-gonic/gin"
	"github.com/hxchjm/log"
	"gorm.io/gorm"
	"net/http"
	"strconv"
)

type UrlInfo struct {
	Url    string
	Method string
}

// 不需要casbin权限校验的路由
var casbinExcludeMap = map[string]struct{}{
	"/api/v1/getinfo|GET":  {},
	"/api/v1/menurole|GET": {},
	"/api/v1/deptTree|GET": {},
	"/api/v1/logout|POST":  {},
}

var casbinExcludeSlice = []UrlInfo{
	{Url: "/api/v1/roleMenuTreeselect/:roleId", Method: "GET"},
}

func AuthCheckRole() gin.HandlerFunc {
	return func(c *gin.Context) {
		defer c.Abort()

		v, ok := c.Get(jwtauth.ContextJwtClaim)
		if !ok {
			c.JSON(http.StatusOK, ecode.Wrap(ecode.ERRToken, "not found token info")) //fmt.Errorf("%s", "not found claim"))
			return
		}
		claim, ok := v.(*jwtauth.CustomClaims)
		if !ok {
			c.JSON(http.StatusOK, ecode.Wrap(ecode.ERRToken, "parse token error"))
			return
		}
		if claim.RoleKey == "admin" {
			c.Next()
			return
		}
		pt := fmt.Sprintf("%s|%s", c.Request.URL.Path, c.Request.Method)
		if _, ok = casbinExcludeMap[pt]; ok {
			c.Next()
			return
		}
		for _, u := range casbinExcludeSlice {
			if util.KeyMatch2(c.Request.URL.Path, u.Url) && c.Request.Method == u.Method {
				c.Next()
				return
			}
		}
		allow, err := cas.GetIns().Enforce(claim.RoleKey, c.Request.URL.Path, c.Request.Method)
		if err != nil {
			log.Errorf(c, "AuthCheckRole error:%s method:%s path:%s", err, c.Request.Method, c.Request.URL.Path)
			c.JSON(http.StatusOK, ecode.Wrap(ecode.ERRToken, "casbin enforce error"))
			return
		}
		if allow {
			c.Next()
		} else {
			c.JSON(http.StatusOK, gin.H{
				"code": 403,
				"msg":  fmt.Sprintf("对不起，您没有接口(%s)的访问权限，请联系管理员", c.Request.URL.Path),
			})
			return
		}
	}
}

func DataScope(ctx context.Context) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		/*		if !config.ApplicationConfig.EnableDP {
				return db
			}*/
		claims := jwtauth.GetClaims(ctx)
		switch claims.DataScope {
		case "2":
			return db.Where(".create_by in (select sys_user.user_id from sys_role_dept left join sys_user on sys_user.dept_id=sys_role_dept.dept_id where sys_role_dept.role_id = ? and deleted_at is null)", claims.RoleId)
		case "3":
			return db.Where("create_by in (SELECT user_id from sys_user where dept_id = ? and deleted_at is null)", claims.DeptId)
		case "4":
			return db.Where("create_by in (SELECT user_id from sys_user where sys_user.dept_id in(select dept_id from sys_dept where dept_path like ? ) and deleted_at is null)", "%/"+strconv.Itoa(claims.DeptId)+"/%")
		case "5":
			return db.Where("create_by = ?", claims.UID)
		default:
			return db
		}
	}
}
